//
//  ActiveAIChatExt.swift
//  imprint
//
//  Created by 小柠檬🍋 on 2025/3/11.
//

import Foundation
import SwiftUI

//检查是否有需要回复
class ActiveChatExt : BaseViewModel {
    static let instance = ActiveChatExt()
    
    private var mapDelay: [String:Bool] = [:]
    private let modeType = IAiModelType.chat.rawValue
    private let modeType2 = IAiModelType.chat2.rawValue
    private let mapQueue = DispatchQueue(label: "mapDelayQueue")
    private let tag = "checkChat"
    
    private func getKey( _ aiRoleId : String?) -> String {
        return aiRoleId ?? ""
    }
    
    func getMapValue(_ key: String) -> Bool {
        return mapQueue.sync {
            self.mapDelay[key] ?? false
        }
    }
    
    func putMapValue(_ key: String,_ bool: Bool) {
        return mapQueue.sync {
            self.mapDelay[key] = bool
        }
    }
    
    func removeMapValue(_ key: String) {
        return mapQueue.sync {
            self.mapDelay.removeValue(forKey: key)
        }
    }
    
    func checkChat() {
        request(isLoading: false,timeout: 60 * 60){
            var listAiRoleReply : [AiRoleBean] = []
            let listAiRole = try await BackupsManager.shared.getDelegateConfig()?.getAiRoleList(false) ?? []
            for aiRole in listAiRole {
                showLog(self.tag, "检查\(String(describing: aiRole.name))的聊天信息")
                let lastChatBean = try await BackupsManager.shared.getDelegateDiary()?.queryNewChat(aiUserId: aiRole.objectId ?? "", userId: BackupsManager.shared.backupsType == BackupsType.cloud ? userManager.getUserId() : "")
                //如果最后一条消息是用户的，则需要主动发起回复
                if (lastChatBean?.type == IChatType.USER.rawValue) {
                    listAiRoleReply.append(aiRole)
                }
                
            }
            return listAiRoleReply
        } suc: { list in
            list.forEach {
                self.doAiReply(aiRole: $0, active:  false)
            }
        } fail: { _ in
            
        }
    }
    
    func doAiReply(aiRole: AiRoleBean?, active: Bool, backup: Bool = false) {
        var errorApi = ""
        request(isLoading: false,timeout: 60 * 60){ [self] in
            //            try check(self.tag,self.toggleAi) {
            //                "AI 功能已关闭"
            //            }
            try check(self.tag, AiChatExt.isAiEnabled() || AiCustomUtils.shared.isCustomAi(type: self.modeType), "AI 功能已用尽,请前往活动领取次数：\(String(describing: aiRole?.name))") {
                DispatchQueue.main.async {
                    if backup == false {
                        showBtnDialog(text: "AI 功能已用尽,请前往活动领取次数") {
                            pathManager.jump(type: JumpType.AI_SET_VIEW, data: AiSetView.FromType.FROM_ACT)
                        }
                    }
                }
            }
            try check(self.tag, aiRole != nil) {
                "没有角色"
            }
            let exit  = self.getMapValue(self.getKey(aiRole?.objectId))
            try check(self.tag, exit == false) {
                "该日记角色已进入延迟阶段"
            }
            self.putMapValue(self.getKey(aiRole?.objectId ?? ""),true)
            let userId = BackupsManager.shared.backupsType == BackupsType.cloud ? userManager.getUserId() : ""
            let listAll = try await BackupsManager.shared.getDelegateDiary()?.queryChat(aiUserId: aiRole?.objectId ?? "", userId: userId, pageNo: 0, pageSize: AiCustomUtils.shared.isCustomAi(type: modeType) ? 200 : 80) ?? []
            for chatBean in listAll {
                //要先处理聊天内容
                try await AiChatConvertExt.dealChat(chatBean)
            }
            var listFinalAll = listAll
            //需要计算超过2天则不关联数据，暂时不处理
            //
            listFinalAll = listFinalAll.reversed() //需要倒序
            try check(self.tag, active || listFinalAll.isEmpty == false) {
                "数据为空，不继续评论"
            }
            try check(self.tag, active || listFinalAll.last?.role?.isUser() == true) {
                "最后一条信息不是用户"
            }
            var replyStr : String = ""
            var tokens : Int64 = 0
            let botRoleBean = RoleBean.get(aiRole!)
            if backup {
                //启动备用方案
                try await retry(maxRetries: 3, retryDelayMillis: 500) {
                    let aiModeBean = configManager.getConfig().getAiChatMode2(key: self.modeType)
                    errorApi = "\(aiModeBean.host ?? ""),\(aiModeBean.model ?? "")"
                    let bean = AIChatRequestBean(active: active, model : aiModeBean.model, list: listFinalAll, botRoleBean: botRoleBean)
                    showLog(self.tag, "请求AI：\(String(describing: toJson(bean)))")
                    let result = try await AiNetManager.shared.requestAI(host: aiModeBean.host, token: aiModeBean.token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                    replyStr = result.getReplyStr()
                    tokens = result.getToken()
                    showLog(self.tag, replyStr)
                }
            } else if AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                //自定义
                try await retry(maxRetries: 3, retryDelayMillis: 500) {
                    let host = AiCustomUtils.shared.getCustomHost(type: self.modeType)
                    let token = AiCustomUtils.shared.getCustomToken(type: self.modeType)
                    let model = AiCustomUtils.shared.getCustomModel(type: self.modeType)
                    errorApi = "\(host),\(model)"
                    let bean = AIChatRequestBean(active: active, model : model, list: listFinalAll, botRoleBean: botRoleBean)
                    showLog(self.tag, "请求AI：\(String(describing: toJson(bean)))")
                    let result = try await AiNetManager.shared.requestAI(host: host, token: token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                    replyStr = result.getReplyStr()
                    tokens = result.getToken()
                    showLog(self.tag, "回复内容：\(replyStr)")
                }
            } else if IChatModelType.TYPE_1 == AppStorageManager.shared.aiModel {
                //模型2
                try await retry(maxRetries: 3, retryDelayMillis: 500) {
                    let aiModeBean = configManager.getConfig().getAiChatMode(key: self.modeType2)
                    errorApi = "\(aiModeBean.host ?? ""),\(aiModeBean.model ?? "")"
                    let bean = AIChatRequestBean(active: active, model : aiModeBean.model, list: listFinalAll, botRoleBean: botRoleBean)
                    showLog(self.tag, "请求AI：\(String(describing: toJson(bean)))")
                    let result = try await AiNetManager.shared.requestAI(host: aiModeBean.host, token: aiModeBean.token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                    replyStr = result.getReplyStr()
                    tokens = result.getToken()
                    showLog(self.tag, "回复内容：\(replyStr)")
                    showLog(self.tag, "回复内容：\(replyStr)")
                }
            } else {
                //模型1
                let aiModeBean = configManager.getConfig().getAiChatMode(key: self.modeType)
                errorApi = "\(aiModeBean.host ?? ""),\(aiModeBean.model ?? "")"
                let bean = AIChatRequestBean(active: active, model : aiModeBean.model, list: listFinalAll, botRoleBean: botRoleBean)
                showLog(self.tag, "请求AI：\(String(describing: toJson(bean)))")
                let result = try await AiNetManager.shared.requestAI(host: aiModeBean.host, token: aiModeBean.token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                replyStr = result.getReplyStr()
                tokens = result.getToken()
                showLog(self.tag, "回复内容：\(replyStr)")
            }
            
            //AI含有违禁词
            if isAiReplyProhibit(replyStr) {
                throw MyError.netFail(ERROR.NET_ERRPR.rawValue, replyStr)
            }
            
            let listMsg = try await self.parseJson(reply: replyStr)
            var chatBean: ChatBean? = nil
            
            for chatMessageBean in listMsg {
                //避免一些错误格式混入
                try check(!(chatMessageBean.content ?? "").contains("type")) {
                    "解析失败"
                }
                switch(chatMessageBean.type) {
                case IAiContentType.TEXT.rawValue:
                    let quote = chatMessageBean.quote_reply
                    //由于格式的乱入，会导致type传text,所以引用有2种，1是type = quote_reply,2是对象不为空
                    if (quote != nil) {
                        let content = (chatMessageBean.reply_content ?? "").isEmpty == false ? chatMessageBean.reply_content : chatMessageBean.content
                        let targetId = chatMessageBean.target_id
                        var quote = ChatMessageBean.Quote()
                        quote.target_id = targetId //引用id
                        quote.target_sender = userManager.getName()
                        quote.target_content = nil //需要根据targetId获取
                        quote.reply_content = content
                        chatBean = try await self.addChat(contentType: IChatContentType.TYPE_CONTENT_TARGET.rawValue, str: content ?? "", botRoleBean: botRoleBean, tokens: tokens, extra: toJson(quote))
                    } else {
                        //正常文本
                        chatBean = try await self.addChat(contentType: IChatContentType.TYPE_CONTENT.rawValue, str: chatMessageBean.content ?? "", botRoleBean: botRoleBean, tokens: tokens)
                    }
                    break
                case IAiContentType.IMAGE.rawValue:
                    //其实没必要坚持是否含有key,反正是根据类型
//                    let emojiPictureKey = EmojiPictureUtils.shared.containsEmojiPicture(chatMessageBean.content ?? "")
                    let emojiPictureKey = chatMessageBean.content ?? ""
                    chatBean = try await self.addEmojiPicture(emojiPictureKey: emojiPictureKey, botRoleBean: botRoleBean, tokens: tokens)
                    break
                case IAiContentType.QUOTE_REPLY.rawValue:
                    let content = (chatMessageBean.reply_content ?? "").isEmpty == false ? chatMessageBean.reply_content : chatMessageBean.content
                    let targetId = chatMessageBean.target_id
                    var quote = ChatMessageBean.Quote()
                    quote.target_id = targetId //引用id
                    quote.target_sender = userManager.getName()
                    quote.target_content = nil //需要根据targetId获取
                    quote.reply_content = content
                    chatBean = try await self.addChat(contentType: IChatContentType.TYPE_CONTENT_TARGET.rawValue, str: content ?? "", botRoleBean: botRoleBean, tokens: tokens, extra: toJson(quote))
                    break
                case IAiContentType.VOICE_MESSAGE.rawValue:
                    //需要去除动作描述
                    let content = AiChatExt.deleteActionDesc(chatMessageBean.content ?? "")
                    let soundBean = SoundBean()
                    //根据文字计算时长
                    soundBean.duration = SoundExt.calculateDuration(text: content ?? "")
                    chatBean = try await self.addChat(contentType: IChatContentType.TYPE_VOICE_MESSAGE.rawValue, str: chatMessageBean.content ?? "", botRoleBean: botRoleBean, tokens: tokens, extra: toJson(soundBean))
                    break
                case IAiContentType.TYPE_ACTION.rawValue:
                    var suffix = chatMessageBean.suffix ?? ""
                    // 判断是否以“你的”开头
                    if suffix.hasPrefix("你") {
                        suffix.removeFirst()  // 直接修改原字符串
                    }
                    var pat = ChatMessageBean.Pat()
                    pat.userId = userManager.getUserId()
                    pat.userName = userManager.getName()
                    pat.roleType = IRoleType.USER.rawValue
                    pat.action = chatMessageBean.action ?? "拍了拍"
                    pat.content = chatMessageBean.content
                    pat.suffix = suffix
                    chatBean = try await self.addChat(contentType: IChatContentType.TYPE_ACTION.rawValue, str: chatMessageBean.content ?? "", botRoleBean: botRoleBean, tokens: tokens, extra: toJson(pat))

                    break
                case .none:
                    chatBean = nil
                    break
                case .some(_):
                    chatBean = nil
                    break
                }
                try await Task.delay(1000)
            }
            return chatBean ?? ChatBean()
        } suc: { bean in
            if !AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                AiChatExt.deductAiChatCountCommon()
            }
            self.removeMapValue(self.getKey(aiRole?.objectId ?? ""))
            //            //发送通知
            //            NotificationCenter.default.post(name: .addChat, object: bean)
            if commonManager.isBackground {
                showLocalNotification(aiRole?.name ?? "", bean.content ?? "")
            }
        } fail: { it in
            self.removeMapValue(self.getKey(aiRole?.objectId ?? ""))
            if ERROR.NET_ERRPR.rawValue == it.code {
                AiChatExt.reportError(
                    type: self.modeType,
                    typeName: "聊天",
                    message: it.realMessage,
                    errorApi: errorApi)
                
                if let error = configManager.getConfig().getAiError(content: it.realMessage) {
                    showToast(error)
                }
            } else {
                //非自定义使用备用方案
                if !backup && !AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                    showLog(self.tag, "聊天使用备用方案")
                    self.doAiReply(aiRole: aiRole, active: active, backup: true)
                }
            }
            
        }
        
    }
    
    private func parseJson(reply: String) async throws -> [ChatMessageBean] {
        //解析字符串, 如果解析失败则为reply
        let json = reply.extractJson() ?? reply
        try check(json.isEmpty == false) {
            "解析json为空"
        }
        var list :[ChatMessageBean] = []
        do {
            //1、先按照格式解析ChatResponseBean
            if let chatResponseBean = try fromJson(json,ChatResponseBean.self), let chatResponse = chatResponseBean.chatResponse  {
                list = chatResponse
                return list
            }
        } catch {
            showLog(tag, "解析ChatResponseBean失败")
        }
        
        do {
            //2、先解析数组
            if let listMessage = try fromJson(json,[ChatMessageBean].self) {
                list = listMessage
                return list
            }
        } catch {
            showLog(tag, "解析[ChatMessageBean]失败")
        }
        do {
            //3、不是数组，解析对象ChatMessageBean
            if let chatMessageBean = try fromJson(json, ChatMessageBean.self) {
                list = [chatMessageBean]
                return list
            }
        } catch {
            showLog(tag, "解析ChatMessageBean失败")
        }
        //4、那就是存文本
        let chatMessageBean = ChatMessageBean()
        chatMessageBean.content = reply
        chatMessageBean.type = IAiContentType.TEXT.rawValue
        list = [chatMessageBean]
        return list
    }
    
    //添加表情包
    private func addEmojiPicture(
        emojiPictureKey: String,
        botRoleBean: RoleBean,
        tokens : Int64
    ) async throws -> ChatBean? {
        let userId = BackupsManager.shared.backupsType == BackupsType.cloud ? userManager.getUserId() : ""
        let emojiPictureBean = try await EmojiPictureUtils.shared.getEmojiPicture(key: emojiPictureKey)
        //开始保存数据
        let chatBean = ChatBean()
        chatBean.type = IChatType.BOT.rawValue
        chatBean.contentType = IChatContentType.TYPE_EMOJI_PICTURE.rawValue
        chatBean.role = botRoleBean
        chatBean.content = emojiPictureBean?.text
        chatBean.time = getMillisecond(try await getNetTime())
        chatBean.aiUserId = botRoleBean.roleId
        chatBean.userId = userId
        chatBean.tokens = tokens
        chatBean.read = false
        chatBean.extra = toJson(emojiPictureBean)
        try await retry(maxRetries: 10, retryDelayMillis: 500) {
            _ = try await BackupsManager.shared.getDelegateDiary()?.addChat(bean: chatBean)
        }
        //发送通知
        NotificationCenter.default.post(name: .addChat, object: chatBean)
        return chatBean
    }
    
    //普通文字
    private func addChat(
        contentType: Int,
        str: String,
        botRoleBean: RoleBean,
        tokens : Int64,
        extra: String? = nil
    ) async throws -> ChatBean? {
        let newStr = EmojiUtils.deleteNoEmotionContent2(text: str) ?? ""
        if (IChatContentType.TYPE_CONTENT.rawValue == contentType && newStr.isEmpty) {
            //文本类型不支持空的
            return nil
        }
        let userId = BackupsManager.shared.backupsType == BackupsType.cloud ? userManager.getUserId() : ""
        //开始保存数据
        let chatBean = ChatBean()
        chatBean.type = IChatType.BOT.rawValue
        chatBean.contentType = contentType
        chatBean.role = botRoleBean
        chatBean.content = newStr
        chatBean.time = getMillisecond(try await getNetTime())
        chatBean.aiUserId = botRoleBean.roleId
        chatBean.userId = userId
        chatBean.tokens = tokens
        chatBean.read = false
        chatBean.extra = extra
        try await retry(maxRetries: 10, retryDelayMillis: 500) {
            _ = try await BackupsManager.shared.getDelegateDiary()?.addChat(bean: chatBean)
        }
        //发送之前，要先处理聊天内容
        try await AiChatConvertExt.dealChat(chatBean)
        //发送通知
        NotificationCenter.default.post(name: .addChat, object: chatBean)
        return chatBean
    }
}

